#include <string.h>
#include <stdlib.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "diskio.h"
#include "pff.h"

#define DELAY 2
#define N 512

volatile uint8_t meas = 1;
uint8_t t[6];	// sec, min, hr, d, m, y
uint8_t buf1[6][16];
DWORD seek = 0;
signed long buf2[2][16];

ISR(TIMER0_COMPA_vect)
{
	t[0]++;
	TCNT0H = 0;		TCNT0L = 0;
	//meas = 1;
}

void clockerna(uint8_t data, char ending, WORD *w)
{
	char tmp[8];
	itoa(data, tmp, 10);
	if(data>9) pf_write(tmp, 2, w);
	else {	pf_write("0", 1, w);	pf_write(tmp, 1, w);}
	if(ending)	pf_write(&ending, 1, w);
}

void dump(void)
{
	uint8_t i, j=0;
	char buf[10];

	WORD w;
	FATFS fs;

	pf_mount(&fs);
	pf_open("data0.txt");
	pf_lseek(seek);
	for(i=0;i<16;i++)
	{
		clockerna(buf1[2][i], ':', &w);
		clockerna(buf1[1][i], ':', &w);
		clockerna(buf1[0][i], '-', &w);
		clockerna(buf1[3][i], '.', &w);
		clockerna(buf1[4][i], '.', &w);
		//clockerna(buf1[5][i], ' ', &w);
		pf_write(" ", 1, &w);
		
		ltoa(buf2[0][i], buf, 10);
		pf_write(buf, strlen(buf), &w);
		for(j=w;j<7;j++)	pf_write(" ", 1, &w);
		pf_write(" ", 1, &w);
		ltoa(buf2[1][i], buf, 10);
		pf_write(buf, strlen(buf), &w);
		for(j=w;j<7;j++)	pf_write(" ", 1, &w);
		pf_write("\n", 1, &w);
	}
	pf_write(0, 0, &w);
	pf_mount(0);
	seek += 512;
}

void set_time(void)
{
	char buf[8];
	uint8_t i;

	WORD w;
	FATFS fs;

	pf_mount(&fs);
	pf_open("kello.txt");

	pf_read(&buf, 2, &w);
	t[2] = atoi(buf);			// Set hours
	pf_read(&buf, 1, &w);
	pf_read(&buf, 2, &w);
	t[1] = atoi(buf);			// Set min

	for(i=3;i<6;i++)
	{
		pf_read(&buf, 1, &w);
		pf_read(&buf, 2, &w);
		t[i] = atoi(buf);		// Set day, month and year
	}

	pf_mount(0);
}

void measure(signed long *res, uint8_t *off, uint8_t pin)
{
	PORTA = pin;										// Switch bridge on
	_delay_ms(DELAY);
	int16_t i;
	for(i=0;i<N;i++)
	{
		ADCSRA |= (1<<ADSC);
		loop_until_bit_is_set(ADCSRA, ADSC);
		*res += (signed long) (ADCW - *off);			// Read
	}
	PORTA = 0;											// Switch bridge off
}

uint8_t measure_polarity(uint8_t pin)
{
	ADCSRB |= (1<<BIN);
	PORTA = pin;										// Switch bridge on
	_delay_ms(DELAY);
	int16_t i;
	long tmp = 0;
	for(i=0;i<N;i++)
	{
		ADCSRA |= (1<<ADSC);
		loop_until_bit_is_set(ADCSRA, ADSC);
		tmp += ADCW;									// Read
	}
	PORTA = 0;											// Switch bridge off
	ADCSRB &= ~(1<<BIN);
	if(tmp > 261632)	return 1;
	else 				return 0;
}

int main (void)
{
	DDRA  = 0b10011100;
	PORTA = 0;
	DDRB  = 0b01001110;
	PORTB = 0b00001011;

	signed long res = 0;
	uint8_t k=0, l=0, off, i, neg;
	uint16_t j;

	ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);		// ADC Enable, 62.5 kHz
	ADCSRB |= (1<<MUX5) | (1<<GSEL);					// MUX5 and Gain select
	//ADMUX = 0b01000000;								// AREF pin enabled
	DIDR0 |= (1<<ADC5D) | (1<<ADC4D) | (1<<ADC1D) | (1<<ADC0D);	// Disable digital output
	PRR |= (1<<PRTIM1);									// Shut down Timer 1
	TCCR0A |= (1<<TCW0);								// Enable 16-bit mode
	TCCR0B |= (1<<CS02);								// Div 256 => 15625 Hz
	TIMSK |= (1<<OCIE0A);								// Interrupt enable
	OCR0B = 0x3d;	OCR0A = 0x09;						// 0x3d09 = 15625 => 1 sec
	sei();												// Enable global interrupts

	ADMUX |= 0b11000;									// ADC0-ADC0, 20x/32x gain
	_delay_ms(250);

	for(j=0;j<512;j++)
	{
		ADCSRA |= (1<<ADSC);
		loop_until_bit_is_set(ADCSRA, ADSC);
		res += ADCW;									// Read
	}
	
	//ADCSRA |= (1<<ADSC);
	//loop_until_bit_is_set(ADCSRA, ADSC);
	off = (uint8_t) res/512;							// Offset 1

	ADMUX &= ~0b11000;									// Clear

	measure(&res, &off, 1<<2);							// Dry run
	set_time();											// Load time from a file
	_delay_ms(DELAY);

	while(1)
	{
		if(t[0]>59){	t[0]=0;	t[1]++; meas=1;}		// Sec check
		if(t[1]>59){	t[1]=0;	t[2]++;}				// Min check
		if(t[2]>23){	t[2]=0; t[3]++;}				// Hr check
		if(t[4]==1 || t[4]==3 || t[4]==4 || t[4]==5 || t[4]==8 || t[4]==10 || t[4]==12)
			if(t[3]>31){	t[3]=1;	t[4]++;}			// Day check
		if(t[4]==6 || t[4]==7 || t[4]==9 || t[4]==11)
			if(t[3]>30){	t[3]=1;	t[4]++;}			// Day check
		if(t[4]==2)
			if(t[3]>28){	t[3]=1;	t[4]++;}			// Day check
		if(t[4]>12){	t[4]=0;	t[5]++;}				// Month check

		if(meas)
		{
			neg = measure_polarity(1<<4);
			if(neg)	ADMUX ^= (1<<1);					// Change polarity on ADC
			
			res = 0;
			measure(&res, &off, (1<<4));
			ADMUX ^= (1<<1);							// Change polarity on ADC
			measure(&res, &off, (1<<7));

			if(neg)	res = -res;
			
			if(k++)
			{
				ADMUX &= ~0b01110;						// Clear
				for(i=0;i<6;i++)	buf1[i][l] = t[i];	// Save time
				buf2[1][l] = res;						// Save result 2
				if(++l>15){	dump();	l = 0;}				// Dump data
				k = 0;	meas = 0;						// Clear stuff
			}
			else
			{
				ADMUX &= ~0b00010;						// Clear
				ADMUX |= 0b01100;						// ADC4-ADC5, 20x/32x gain
				buf2[0][l] = res;						// Save result 1
			}
		}
	}

	return 0;
}